package org.raymond.icloud.common.core.util;

import cn.hutool.core.collection.ConcurrentHashSet;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Sets;
import org.raymond.icloud.common.core.constants.ErrorCode;
import org.raymond.icloud.common.core.exception.BaseException;
import org.springframework.util.AntPathMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RequestUtil {
    private static final Pattern authorizationPattern = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+)=*$", 2);

    private static final AntPathMatcher checkIgnoresMatch = new AntPathMatcher();
    private static final AntPathMatcher logIgnoresMatch = new AntPathMatcher();
    private static final Set<String> checkIgnores = Sets.newLinkedHashSet("/", "/error","/favicon.ico",
            "/**/v3/api-docs/**","/**/swagger-resources/**","/webjars/**","/swagger-ui/**/*","/swagger-ui.html",
            "/doc.html","/actuator/**","/druid/**"
    );

    private static final Set<String> logIgnores = Sets.newLinkedHashSet("/", "/favicon.ico",
            "/**/v3/api-docs/**","/**/swagger-resources/**","/webjars/**","/swagger-ui/**/*","/swagger-ui.html",
            "/doc.html",
            "/actuator/**","/druid/**"
    );

    private RequestUtil(){}

    public static String resolve(HttpServletRequest request) {
        String authorizationHeaderToken = resolveFromAuthorizationHeader(request);
        String parameterToken = resolveFromRequestParameters(request);
        if (StringUtils.isNotBlank(authorizationHeaderToken)) {
            if (StringUtils.isNotBlank(parameterToken)) {
                throw new BaseException(ErrorCode.UNAUTHORIZED.getCode(), "token格式错误");
            } else {
                return authorizationHeaderToken;
            }
        } else {
            return parameterToken;
        }
    }

    public static boolean notCheck(String requestPath) {
        return checkIgnores.stream().anyMatch(e->checkIgnoresMatch.match(e, requestPath));
    }

    public static boolean noLog(String requestPath){
        return logIgnores.stream().anyMatch(e->logIgnoresMatch.match(e, requestPath));
    }

    public static String getRelativePath(HttpServletRequest request){
        String contextPath = request.getContextPath();
        String requestUri = request.getRequestURI();
        return requestUri.substring(contextPath.length());
    }

    private static String resolveFromAuthorizationHeader(HttpServletRequest request) {
        String authorization = request.getHeader("token");
        if (StringUtils.startsWithIgnoreCase(authorization, "bearer")) {
            Matcher matcher = authorizationPattern.matcher(authorization);
            if (!matcher.matches()) {
                throw new BaseException(ErrorCode.UNAUTHORIZED.getCode(), "token格式错误");
            } else {
                return matcher.group("token");
            }
        } else {
            return null;
        }
    }

    private static String resolveFromRequestParameters(HttpServletRequest request) {
        String[] values = request.getParameterValues("token");
        if (values != null && values.length != 0) {
            if (values.length == 1) {
                return values[0];
            } else {
                throw new BaseException(ErrorCode.UNAUTHORIZED.getCode(), "token格式错误");
            }
        } else {
            return null;
        }
    }
}
